package com.easy;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.poidemo.ExcelModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 直接用map接收数据
 *
 * @author haibo zhu
 */
public class NoModelDataListener extends AnalysisEventListener<Map<Integer, String>> {
    private static final Logger LOGGER = LoggerFactory.getLogger(NoModelDataListener.class);
    /**
     * 每隔5条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 50000;
    List<Map<Integer, String>> list = new ArrayList<>();
    private ExcelModel excelModel;
    private int count = 0;
    private final List<List<String>> headerList = new ArrayList<>();

    /**
     * 这里会一行行的返回头
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        headMap.forEach((k, v) -> {
            List<String> list = new ArrayList<>();
            list.add(v);
            headerList.add(list);
        });
        LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
        LOGGER.info("列表头={}", head());
        if (null == this.excelModel) {
            excelModel = new ExcelModel(context.readSheetHolder().getSheetName(), getTotals(context), BATCH_COUNT, getFileCount(context), true, false);
        }

    }

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        LOGGER.info("所有数据解析完成！");

    }

    /**
     * 处理数据
     */
    private void saveData() {
        LOGGER.info("{}条数据，开始分割数据！", list.size());
        int endRow = count * this.excelModel.getFileSize();
        int startRow = (endRow - this.excelModel.getFileSize()) + 1;
        startRow += BATCH_COUNT;
        endRow += BATCH_COUNT;
        if (endRow >= this.excelModel.getTotalRows()) {
            endRow = this.excelModel.getTotalRows();
        }

        String path = this.getClass().getResource("").getPath();

        String fileName = this.excelModel.getSheetName() + startRow + "_" + endRow + ".xlsx";
        List<List<Object>> datalist = new ArrayList<>();

        list.forEach(map -> {
            List<Object> row = new ArrayList<>();
            map.forEach((k, v) -> row.add(v));
            datalist.add(row);
        });

        // 这里 需要指定写用哪个class去写，然后写到第一个sheet，名字为模板 然后文件流会自动关闭

        long beginTime = System.currentTimeMillis();
        EasyExcel.write(path + fileName).head(head()).useDefaultStyle(false).sheet(fileName).doWrite(datalist);
        LOGGER.info("分割文件{},执行耗时{}秒", fileName, (System.currentTimeMillis() - beginTime) / 1000f);
        count++;
        LOGGER.info("数据写入文件成功！");
    }

    private List<List<String>> head() {
        return headerList;
    }

    private int getTotals(AnalysisContext context) {
        return context.readSheetHolder().getApproximateTotalRowNumber() - 1;
    }

    private int getFileCount(AnalysisContext context) {
        Integer total = context.readSheetHolder().getApproximateTotalRowNumber();
        int fileCount;
        if ((total - 1) % BATCH_COUNT == 0) {
            fileCount = (total - 1) / BATCH_COUNT;
        } else {
            fileCount = ((total - 1) / BATCH_COUNT) + 1;
        }
        System.out.println("fileCount:" + fileCount);
        return fileCount;
    }

    public static void main(String[] args) {
        // 文件路径参数，分割后每个文件的记录数
        String fileName = NoModelDataListener.class.getClassLoader().getResource("template").getPath()+ File.separator+"商机团队.xlsx";
        long beginTime = System.currentTimeMillis();
        // 这里 只要，然后读取第一个sheet 同步读取会自动finish
        EasyExcel.read(fileName, new NoModelDataListener()).sheet().doRead();
        LOGGER.info("源文件{},总执行耗时{}秒", fileName, (System.currentTimeMillis() - beginTime) / 1000f);
    }

}